#include "internal_types.h"
#include "engine.h"

#include <ctm/openctm.h>
#include <GL/glew.h>

#include <map>
#include <set>

#ifndef BUFFER_OFFSET
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
#endif

namespace HW
{

using namespace Resource;

static CTMcontext lCTMcontext;
static map<string,TTexture> lFileSurfaces;
static set<TTexture> lSurfaces;

TSurface _i_LoadSurface ( const_str path )
{
	string lPath = AbstractPath ( path );

	if ( lFileSurfaces.find ( lPath ) != lFileSurfaces.end() )
	{
		return lFileSurfaces[lPath];
	}

	AppLog ( string("Loading surface: \"" + lPath + "\"").c_str() );

	_i_Surface* lNewSurface = new _i_Surface();
	
	lCTMcontext = ctmNewContext(CTM_IMPORT);

	ctmLoad(lCTMcontext, lPath.c_str());
	if(ctmGetError(lCTMcontext) != CTM_NONE)
	{
		ctmFreeContext(lCTMcontext);
		return NULL;
	}

	lNewSurface->vertNum = ctmGetInteger(lCTMcontext, CTM_VERTEX_COUNT);;
	lNewSurface->trisNum = ctmGetInteger(lCTMcontext, CTM_TRIANGLE_COUNT);

	glGenBuffers ( 6 , lNewSurface->ID );

	glBindBuffer(GL_ARRAY_BUFFER, lNewSurface->positionBufID); //Bind the vertex buffer
	glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * lNewSurface->vertNum, ctmGetFloatArray(lCTMcontext, CTM_VERTICES), GL_STATIC_DRAW); //Send the data to OpenGL

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lNewSurface->indexBufID); //Bind the index buffer
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * 3 * lNewSurface->trisNum, ctmGetIntegerArray(lCTMcontext, CTM_INDICES), GL_STATIC_DRAW); //Send the data to OpenGL

	ctmFreeContext(lCTMcontext);

	lFileSurfaces[lPath] = (TSurface)(lNewSurface);

	lSurfaces.insert ( (TSurface)(lNewSurface) );

	return (TSurface)(lNewSurface);
}

void FreeSurface(TSurface surface)
{
	AppLog ( "Freeing surface." );
	_i_Surface* lSurf = (_i_Surface*)surface;
		
	glDeleteBuffers(6,lSurf->ID);

	lSurfaces.erase ( surface );

	// TODO: Should remove the surface entry in the lFileSurfaces map.
}

void DrawSurface ( TSurface surface )
{
	glEnableClientState(GL_VERTEX_ARRAY);
	glBindBuffer(GL_ARRAY_BUFFER, ((_i_Surface*)surface)->positionBufID);
	glVertexPointer(3, GL_FLOAT, 0, (void *)(GLintptr) 0);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ((_i_Surface*)surface)->indexBufID);
	glDrawElements(GL_TRIANGLES, ((_i_Surface*)surface)->trisNum*3, GL_UNSIGNED_INT , BUFFER_OFFSET(0)); //We are now drawing
}

void _i_InitSurfaces ( void )
{
}

void _i_UnInitSurfaces ( void )
{
	while ( !lSurfaces.empty() )
		FreeSurface ( *lSurfaces.begin() );
}
}